home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 February: Tool Chest / Apple Developer CD Series Tool Chest February 1996 (Apple Computer)(1996).iso / Sample Code / Snippets / Testing & Debugging / Audit / Src / Audit.h < prev    next >
Encoding:
C/C++ Source or Header  |  1993-07-21  |  18.0 KB  |  502 lines  |  [TEXT/MPS ]

  1. /*                                        Audit.h                                    */
  2. /*
  3.  * Audit.h
  4.  * Copyright © 1992-93 Apple Computer Inc. All Rights Reserved.
  5.  * Programmed by Martin Minow,
  6.  *    Internet:    minow@apple.com
  7.  *    AppleLink:    MINOW
  8.  * Version of January 14, 1993
  9.  *
  10.  * Edit History
  11.  *    93.01.09 MM        First public release
  12.  *    93.01.14 MM        Think and MPW generate different record sizes; a disaster if
  13.  *                    you create an Audit Record under Think and call Audit compiled
  14.  *                    under MPW. Also added a test for record sizes and included
  15.  *                    record size information in the AuditRecord.
  16.  *    93.07.09 MM        Conversion to Think C 6.0, text reformatted for standard
  17.  *                    page layout, no substantive changes 
  18.  *
  19.  * This file contains the unique definitions used for driver and code-segment
  20.  * logging.
  21.  *
  22.  * Note: because Pascal does not support variable-length calling sequences,
  23.  * the functions are C-format only.
  24.  */
  25. #ifndef __Audit__
  26. #define __Audit__
  27.  
  28. #include <stdarg.h>
  29. #include <OSUtils.h>
  30. #include <Processes.h>
  31.  
  32. /*
  33.  * To create an audit record, a driver, application, or other code segment calls
  34.  * InitAudit(). This is the only function that accesses the memory manager. The
  35.  * audit record is created on the System Heap.
  36.  *
  37.  * To obtain a reference to an audit record, a code segment calls GetAuditPtr().
  38.  * This may be called at any time.
  39.  *
  40.  * Both InitAudit and GetAuditPtr are moderately inefficient (they call Gestalt()).
  41.  * Thus, a driver (etc.) should store the value in a private variable. For example,
  42.  * a driver would typically store the value in a variable in its driver control
  43.  * block. The Audit Record never moves in memory.
  44.  *
  45.  * Once an audit area has been created for a particular Gestalt selector,
  46.  * it persists in its current form until the computer is re-booted.
  47.  *
  48.  * The display application processes log entries as follows. Note
  49.  * that all functions may be safely called with a NULL auditPtr:
  50.  *
  51.  *        gAuditPtr = GetAuditPtr(kMyAuditSelector);
  52.  *        GetCurrentProcess(&gOldLogProcess);
  53.  *        WakeUpAudit(gAuditPtr, &gOldProcess);
  54.  *        wasLogging = EnableAudit(gAuditPtr, TRUE);
  55.  *        while (gQuitNow == FALSE) {
  56.  *            ProcessOneEvent();
  57.  *            for (i = 0; i < 100; i++) {
  58.  *                if (ReadAudit(gAuditPtr, &missed, &logEntry) == FALSE)
  59.  *                    break;
  60.  *                else {
  61.  *                    Str255        timeText, dataText;
  62.  *
  63.  *                    FormatAuditEntryTimestamp(gAuditPtr, &logEntry, timeText);
  64.  *                    FormatAuditEntryData(&ENTRY, dataText);
  65.  *                    DisplayString(timeText);
  66.  *                    DisplayString(dataText);
  67.  *                }
  68.  *            }
  69.  *        }
  70.  *        EnableAudit(gAuditPtr, wasLogging);
  71.  *        WakeUpCurrentProcess(&gOldLogProcess);
  72.  *        ExitToShell();
  73.  */
  74.  
  75. /*
  76.  * Each audit record entry contains the following information:
  77.  *        tickCount        The Ticks value at the time the data was collected.
  78.  *        lostData        The number of audit records that were not stored before
  79.  *                        this one because Audit was called when there were no free
  80.  *                        records available.
  81.  *        idCode            A longword that uniquely identifies the log entry (i.e.,
  82.  *                        who logged it). This is provided by the Audit caller.
  83.  *        format            A longword that describes the format of the log data.
  84.  *        data[8]            eight longwords that contain the entry-unique information.
  85.  *                        The actual conte is defined by the format longword.
  86.  * TickCount and lostData are maintained by the Audit library, while the other
  87.  * parameters are copied from the Audit parameters. Each entry is time-stamped by
  88.  * the following algorithm:
  89.  *        elapsedTicks = RECORD.tickCount - LOG.ticksAtStart;
  90.  *        SecsToDate(
  91.  *            LOG.timeAtStart + elapsedTicks / 60,
  92.  *            &logEntryDateString
  93.  *        );
  94.  *        printf(, ..., date.second, elapsedTicks % 60);
  95.  * AuditRead returns a copy of the current audit record. See AuditEntryFormat.c
  96.  * and AuditDCMD.c for record formatting examples. Note that, because of the way
  97.  * formatting data is stored, changing the size of data[] is very difficult --
  98.  * and not recommended.
  99.  */
  100. typedef struct AuditEntry {
  101.     unsigned long            tickCount;    /* TickCount() at Audit call            */
  102.     unsigned long            lostData;    /* Missing records before this one        */
  103.     OSType                    idCode;        /* Why are we logging -- set by caller    */
  104.     unsigned long            format;        /* Format of the data (see below)        */
  105.     unsigned long            data[8];    /* The data itself                        */
  106. } AuditEntry, *AuditEntryPtr;
  107. /*
  108.  * Hand-compute the size to make sure that compiler quirks don't mess us up.
  109.  * We check that kSizeofAuditEntry equals sizeof (AuditEntry). The ANSI C
  110.  * Standard does not permit "sizeof" in a #define statement.
  111.  */
  112. #define kSizeofAuditEntry ((4 * 4) + (4 * 8))
  113.  
  114.  
  115. /*
  116.  * AuditQueueEntry is a private structure (only Audit.c and AuditDCMD.c reference
  117.  * it). It contains the Audit entry record and a queue element pointer that
  118.  * connects this record with other records in the free or to-be-processed queues.
  119.  */
  120. typedef struct AuditQueueEntry {
  121.     QElemPtr                qLink;        /* Queue linkage        */
  122.     AuditEntry                theEntry;    /* User's data area        */
  123. } AuditQueueEntry, *AuditQueueEntryPtr;
  124. #define kSizeofAuditQueueEntry (kSizeofAuditEntry + 4)
  125.  
  126. /*
  127.  * The audit record contains a fixed header with the following information:
  128.  *
  129.  *        lowVersion        The earliest version of the AuditRecord that the library
  130.  *                        that created the record understands.
  131.  *        highVersion        The latest version of the AuditRecord that the library
  132.  *                        that created the record understands.
  133.  *        recordSize        This longword encodes the size of the AuditRecord and
  134.  *                        AuditQueueEntry to ensure that compiler alignment
  135.  *                        considerations do not cause code to crash.
  136.  *        free.queue        An O.S. queue with available log records.
  137.  *        data.queue        An O.S. queue with busy log records.
  138.  *        lostData        The number of records not logged. This is cleared whenever
  139.  *                        Audit successfully stores a caller's request.
  140.  *        PSN                The ProcessSerialNumber of the process to awaken when
  141.  *                        something is logged.
  142.  *        refNum            A longword that is available for your use.
  143.  *        logEnabled        TRUE if logging.
  144.  *        timeAtStart        GetDateTime() when the log was created.
  145.  *        ticksAtStart    TickCount() when the log was created.
  146.  * User software accesses an audit record by calling Audit functions. This is
  147.  * necessary so that the record can be accessed by interrupt-level routines
  148.  * without risk of obtaining inconsistent data.
  149.  *
  150.  * Note: the QHdr structure is not longword aligned. Some compilers add an extra
  151.  * 16-bit word padding. If an AuditRecord is created by code generated by one
  152.  * compiler, and accessed by code generated by the other compiler, disaster ensues.
  153.  * To prevent this, the QHdr structures are encapsulated in a dummy structure that
  154.  * is longword aligned. This is ugly, but the alternative is uglier.
  155.  */
  156. typedef struct AuditRecord {
  157.     union {
  158.       void                *unusedLong;    /* Force longword align    */
  159.       struct {
  160.         unsigned short    low;            /* Earliest lib version    */
  161.         unsigned short    high;            /* Latest lib version    */
  162.       } u;
  163.     } version;
  164.     unsigned long        recordSize;        /* Compiler check        */
  165.     unsigned long        lostData;        /* Missed log counter    */
  166.     void                *refNum;        /* User-controlled long    */
  167.     unsigned long        flags;            /* Logging & lost data    */
  168.     unsigned long        timeAtStart;    /* GetDateTime()        */
  169.     unsigned long        ticksAtStart;    /* TickCount()            */
  170.     ProcessSerialNumber    PSN;            /* Wakeup this process    */
  171.     union {
  172.         QHdr            queue;            /* Free queue header    */
  173.         long            unused[
  174.             (sizeof (QHdr) + (sizeof (long) - 1)) / sizeof (long)
  175.         ];
  176.     } free;
  177.         union {
  178.         QHdr            queue;            /* Data queue header    */
  179.         long            unused[
  180.             (sizeof (QHdr) + (sizeof (long) - 1)) / sizeof (long)
  181.         ];
  182.     } data;
  183.     AuditQueueEntry        entries[1];        /* Entries stored here    */
  184. } AuditRecord, *AuditPtr;
  185. #define kSizeofAuditRecord (                                        \
  186.         + (7 * 4)                    /* Various longwords        */    \
  187.         + (12 * 2)                    /* sizeof QHdr's            */    \
  188.         + sizeof (ProcessSerialNumber)                                \
  189.         + kSizeofAuditQueueEntry                                    \
  190.     )
  191. #define kAuditRecordSize ((unsigned long) (                            \
  192.         ((sizeof (AuditRecord) - sizeof (AuditQueueEntry)) << 16L)    \
  193.         | sizeof (AuditQueueEntry)                                    \
  194.     ))
  195.  
  196. /*
  197.  * Values for the flags variable in the AuditRecord. These are private to the
  198.  * Audit library and dcmd display routine.
  199.  */
  200. #define kAuditEnabledMask        1
  201. #define kAuditPreserveFirstMask    2
  202.  
  203. /*
  204.  * These flags control data formatting. Note: because data is passed using
  205.  * variable-length argument list conventions and we want the code to work
  206.  * compatibly on both Think and MPW, all numeric parameters must be passed as
  207.  * "long" or "unsigned long." For example, to pass an OSErr code, do
  208.  *        Audit(
  209.  *            auditPtr,
  210.  *            'fubr',
  211.  *            AuditFormat1(kAuditFormatSigned),
  212.  *            (signed long) statusCode
  213.  *        );
  214.  */
  215. enum {
  216.     /*
  217.      * Parameters to the AuditFormat macro.
  218.      */
  219.     kAuditFormatSigned            = 0,        /* Signed long            */
  220.     kAuditFormatUnsigned        = 1,        /* Unsigned (decimal)    */
  221.     kAuditFormatHex                = 2,        /* Unsigned (hex/char)    */
  222.     kAuditFormatAddress            = 3,        /* Unsigned hex only    */
  223.     kAuditFormatReserved        = 4,        /* Unused                */
  224.     kAuditFormatLocation        = 5,        /* Location (last fmt)    */
  225.     kAuditFormatString            = 6,        /* String (last format)    */
  226.     kAuditFormatEnd                = 7,        /* End signal (no data)    */
  227.     /*
  228.      * kAuditFormatShift must be large enough to shift all format codes. All data
  229.      * format codes must fit into a single longword.
  230.      */
  231.     kAuditFormatShift        = 3,
  232.     kAuditFormatMask        = (1 << kAuditFormatShift) - 1
  233. };
  234.  
  235. /*
  236.  * The AuditFormat macro stores the format word.
  237.  */
  238. #define AuditFormat(f0, f1, f2, f3, f4, f5, f6, f7)    \
  239.     (  (f0)                                            \
  240.      | ((f1) << (kAuditFormatShift * 1))            \
  241.      | ((f2) << (kAuditFormatShift * 2))            \
  242.      | ((f3) << (kAuditFormatShift * 3))            \
  243.      | ((f4) << (kAuditFormatShift * 4))            \
  244.      | ((f5) << (kAuditFormatShift * 5))            \
  245.      | ((f6) << (kAuditFormatShift * 6))            \
  246.      | ((f7) << (kAuditFormatShift * 7))            \
  247.      | (kAuditFormatEnd << (kAuditFormatShift * 8))    \
  248.     )
  249. #define AuditFormat1(f0)                                                    \
  250.     AuditFormat(                                                            \
  251.         (f0),          kAuditFormatEnd, kAuditFormatEnd, kAuditFormatEnd,    \
  252.         kAuditFormatEnd, kAuditFormatEnd, kAuditFormatEnd, kAuditFormatEnd    \
  253.     )
  254. #define AuditFormat2(f0, f1)                                                \
  255.     AuditFormat(                                                            \
  256.         (f0),          (f1),          kAuditFormatEnd, kAuditFormatEnd,        \
  257.         kAuditFormatEnd, kAuditFormatEnd, kAuditFormatEnd, kAuditFormatEnd    \
  258.     )
  259. #define AuditFormat3(f0, f1, f2)                                            \
  260.     AuditFormat(                                                            \
  261.         (f0),          (f1),          (f2),          kAuditFormatEnd,        \
  262.         kAuditFormatEnd, kAuditFormatEnd, kAuditFormatEnd, kAuditFormatEnd    \
  263.     )
  264. #define AuditFormat4(f0, f1, f2, f3)                                        \
  265.     AuditFormat(                                                            \
  266.         (f0),          (f1),          (f2),          (f3),                    \
  267.         kAuditFormatEnd, kAuditFormatEnd, kAuditFormatEnd, kAuditFormatEnd    \
  268.     )
  269. #define AuditFormat5(f0, f1, f2, f3, f4)                                    \
  270.     AuditFormat(                                                            \
  271.         (f0),          (f1),          (f2),          (f3),                    \
  272.         (f4),          kAuditFormatEnd, kAuditFormatEnd, kAuditFormatEnd    \
  273.     )
  274. #define AuditFormat6(f0, f1, f2, f3, f4, f5)                                \
  275.     AuditFormat(                                                            \
  276.         (f0),          (f1),          (f2),          (f3),                    \
  277.         (f4),          (f5),          kAuditFormatEnd, kAuditFormatEnd        \
  278.     )
  279. #define AuditFormat7(f0, f1, f2, f3, f4, f5, f6)                            \
  280.     AuditFormat(                                                            \
  281.         (f0),          (f1),          (f2),          (f3),                    \
  282.         (f4),          (f5),          (f6),          kAuditFormatEnd        \
  283.     )
  284. #define AuditFormat8(f0, f1, f2, f3, f4, f5, f6, f7)                        \
  285.     AuditFormat(                                                            \
  286.         (f0),          (f1),          (f2),          (f3),                    \
  287.         (f4),          (f5),          (f6),          (f7)                    \
  288.     )
  289.  
  290. /*
  291.  * The driver or code segment calls the following functions to access audit
  292.  * records. InitAudit returns NULL if it couldn't create an audit record. It must
  293.  * be called when memory allocation is permitted (i.e. from an application, init,
  294.  * or a driver open routine).
  295.  *
  296.  * All functions that take an AuditPtr argument are "NULL-safe:" if called with a
  297.  * null parameter, they do nothing (gracefully).
  298.  *
  299.  *        gestaltSelector        Used to identify this audit record to the display
  300.  *                            application.
  301.  *        nEntries            The number of audit entries. Each audit entry consumes
  302.  *                            52 bytes of non-relocatable System Heap space.
  303.  *        initiallyEnabled    TRUE to start logging upon creation. The EnableAudit
  304.  *                            function allows modifying this parameter.
  305.  *        preserveFirst        If TRUE and the entry area fills, preserve the first
  306.  *                            nEntries, losing the newest entry. If FALSE and the
  307.  *                            entry area fills, delete the earliest entry, preserving
  308.  *                            the newest entry. The PreserveAudit function allows
  309.  *                            modifying this parameter.
  310.  * If some other program has already created an audit record with this
  311.  * gestaltSelector, the function returns a pointer to that log record. This is not
  312.  * necessarily an error. For example, it allows a driver to locate a log record
  313.  * that had been created by an init routine. If the init routine did not run,
  314.  * the driver will create the record. This may be useful for developers who are
  315.  * trying to track down obscure "happens only at the customer site" bugs.
  316.  */
  317. AuditPtr                    InitAudit(
  318.         OSType                    gestaltSelector,    /* Gestalt to create        */
  319.         unsigned short            nEntries,            /* Number of audit entries    */
  320.         Boolean                    initiallyEnabled,    /* Start auditing now?        */
  321.         Boolean                    preserveFirst        /* Save earlier entries?    */
  322.     );
  323.  
  324. /*
  325.  * This function writes an audit entry if auditing is enabled.
  326.  *
  327.  *        auditPtr            As returned by AuditInit. If NULL, nothing is logged.
  328.  *        idCode                A user-controlled value, by convention an OSType
  329.  *                            (4-byte character) that identifies this entry. The
  330.  *                            display application prints it. Note that, on the
  331.  *                            Macintosh, an OSType can be coerced from/to any
  332.  *                            longword scalar (such as an address) without loss of
  333.  *                            data. This may be useful for user-written display
  334.  *                            applications.
  335.  *        format                A longword that specifies the format of the remaining
  336.  *                            data. Use the value AuditFormat1(kAuditFormatString)
  337.  *                            if the only datum is a pascal string, otherwise, use
  338.  *                            the AuditFormat macro to create the value.
  339.  *        ...                    Additional data as needed. Note that all data must be
  340.  *                            specified as longwords (StringPtr, address, or long).
  341.  *                            Naturally short integers such as Booleans or OSErr
  342.  *                            codes must be explicitly cast to long. This is needed
  343.  *                            because of differences between Think C and MPW
  344.  *                            compilers.
  345.  */
  346. void                        Audit(
  347.         AuditPtr                auditPtr,    /* Audit Record Pointer                */
  348.         OSType                    idCode,        /* User-specified identifier        */
  349.         unsigned long            format,        /* Format bits                        */
  350.         ...                                    /* Additional data, if any            */
  351.     );
  352.  
  353. /*
  354.  * AuditString calls Audit with a single Pascal string argument
  355.  */
  356. #define AuditString(auditPtr, idCode, string) (            \
  357.         Audit(                                            \
  358.             (auditPtr),                                    \
  359.             (idCode),                                    \
  360.             AuditFormat1(kAuditFormatString),            \
  361.             string                                        \
  362.         )                                                \
  363.     )
  364.  
  365. /*
  366.  * AuditStatusString calls Audit with the status and string values.
  367.  */
  368. #define AuditStatusString(auditPtr, idCode, status, string) ( \
  369.         Audit(                                            \
  370.             (auditPtr),                                    \
  371.             (idCode),                                    \
  372.             AuditFormat2(kAuditFormatSigned, kAuditFormatString), \
  373.             (signed long) (status),                        \
  374.             string                                        \
  375.         )                                                \
  376.     )
  377. /*
  378.  * AuditStatusLocation calls Audit with the function location.
  379.  */
  380. #define AuditStatusLocation(auditPtr, idCode, status) (    \
  381.         Audit(                                            \
  382.             (auditPtr),                                    \
  383.             (idCode),                                    \
  384.             AuditFormat2(kAuditFormatSigned, kAuditFormatLocation), \
  385.             (signed long) (status)                        \
  386.         )                                                \
  387.     )
  388.  
  389. /*
  390.  * Return a pointer to the log area, or NULL if there is none. Note: this can be
  391.  * called at any time (even from a driver completion routine), so exception
  392.  * logging can take place (somewhat inefficiently) even if the AuditPtr is not
  393.  * stored permanently.
  394.  */
  395. AuditPtr                    GetAuditPtr(
  396.         OSType                    gestaltSelector
  397.     );
  398.  
  399. /*
  400.  * Awaken a specified process when data is stored in the audit record. Call by the
  401.  * following sequence:
  402.  *        GetCurrentProcess(&oldPSN);        // process to awaken
  403.  *        WakeUpAudit(auditPtr, &oldPSN);
  404.  *    The previous process is now stored in oldPSN)
  405.  *        ... display the log ...
  406.  *        WakeUpAudit(auditPtr, &oldPSN);    // restore old
  407.  *        ExitToShell();
  408.  * This is normally only called by the display application.
  409.  */
  410. void                        WakeUpAudit(
  411.         AuditPtr                auditPtr,
  412.         ProcessSerialNumber        *oldPSN
  413.     );
  414.  
  415. /*
  416.  * Enable/disable audit logging. Returns the old logging state.
  417.  */
  418. Boolean                        EnableAudit(
  419.         AuditPtr                auditPtr,
  420.         Boolean                    enableLogging
  421.     );
  422.  
  423. /*
  424.  * Return the value of the Audit enable flag. Returns FALSE if auditPtr is NULL or
  425.  * auditing is disabled.
  426.  */
  427. Boolean                        IsAuditEnabled(
  428.         AuditPtr                auditPtr
  429.     );
  430.  
  431. /*
  432.  * Set the preserveAudit flag. Returns the old flag value.
  433.  */
  434. Boolean                        PreserveAudit(
  435.         AuditPtr                auditPtr,
  436.         Boolean                    preserveFirst
  437.     );
  438.  
  439. /*
  440.  * Get the time that the log record was created. This is used to time-stamp log
  441.  * entries.
  442.  */
  443. void                        GetAuditStartTimes(
  444.         AuditPtr                auditPtr,
  445.         unsigned long            *timeAtStart,
  446.         unsigned long            *ticksAtStart
  447.     );
  448.  
  449. /*
  450.  * Read the next audit entry. This returns a copy of the entry, if one is
  451.  * available, and returns TRUE. This function manages all log queues. ReadAudit
  452.  * returns FALSE if no entry is available or auditPtr is NULL.
  453.  */
  454. Boolean                        ReadAudit(
  455.         AuditPtr                auditPtr,
  456.         AuditEntryPtr            thisLogEntry
  457.     );
  458.  
  459. /*
  460.  * Store a user-controlled reference value. This may be coerced to any scalar
  461.  * value (such as a memory pointer or longword). SetAuditRefNum returns the
  462.  * previous value of the refNum, or NULL if no value had been stored.
  463.  */
  464. void                        *SetAuditRefNum(
  465.         AuditPtr                auditPtr,
  466.         void                    *refNum
  467.     );
  468.  
  469. /*
  470.  * Return the current user-controlled reference value. This may be coerced to any
  471.  * scalar value (such as a memory pointer or longword). This returns zero if
  472.  * auditPtr is NULL or no value had been stored.
  473.  */
  474. void                        *GetAuditRefNum(
  475.         AuditPtr                auditPtr
  476.     );
  477.  
  478. /*
  479.  * This function is in AuditEntryFormat.c - it formats an entry into a single line
  480.  * that is stored in the result. Note: only the data is formatted: the timestamp
  481.  * is not processed.
  482.  */
  483. void                        FormatAuditEntryData(
  484.         register AuditEntryPtr    entryPtr,
  485.         StringPtr                result
  486.     );
  487.  
  488. /*
  489.  * This function is in AuditEntryFormat.c - it formats the timestamp into
  490.  * yyyy.mm.dd hh.mm.ss.msec format. Audit does not use the built-in date
  491.  * formatting routines.
  492.  */
  493. void                        FormatAuditEntryTimestamp(
  494.         register AuditPtr        auditPtr,
  495.         register AuditEntryPtr    entryPtr,
  496.         StringPtr                result
  497.     );
  498.  
  499.  
  500. #endif    /* __Audit__    */
  501.  
  502.